PROGRAM Sample;

{ Sample -- A small sample application written by Macintosh User Education }
{ It displays a single, fixed-size window in which the user can enter and edit text. }

{ The following two compiler commands are required for the Lisa Workshop. }
{$X-}  {turn off automatic stack expansion}
{$U-}  {turn off Lisa libraries}

{ The USES clause brings in the units containing the Pascal interfaces. }
{ The $U expression tells the compiler what file to look in for the specified unit. }
USES {$U Obj/MemTypes } MemTypes,   {basic Memory Manager data types}
     {$U Obj/QuickDraw} QuickDraw,  {interface to QuickDraw}
     {$U Obj/OSIntf   } OSIntf,     {interface to the Operating System}
     {$U Obj/ToolIntf } ToolIntf;   {interface to the Toolbox}

CONST appleID = 128;     {resource IDs/menu IDs for Apple, File, and Edit menus}
      fileID  = 129;
      editID  = 130;

      appleM = 1;        {index for each menu in myMenus (array of menu handles)}
      fileM  = 2;
      editM  = 3;

      menuCount = 3;     {total number of menus}

      windowID = 128;    {resource ID for application's window}

      undoCommand  = 1;  {menu item numbers identifying commands in Edit menu}
      cutCommand   = 3;
      copyCommand  = 4;
      pasteCommand = 5;
      clearCommand = 6;

VAR myMenus: ARRAY[1..menuCount] OF MenuHandle; {array of handles to the menus}
    dragRect: Rect;         {rectangle used to mark boundaries for dragging window}
    txRect: Rect;           {rectangle for text in application window}
    textH: TEHandle;        {handle to information about the text}
    theChar: CHAR;          {character typed on the keyboard or keypad}
    extended: BOOLEAN;      {TRUE if user is Shift-clicking}
    doneFlag: BOOLEAN;      {TRUE if user has chosen Quit command}
    myEvent: EventRecord;   {information about an event}
    wRecord: WindowRecord;  {information about the application window}
    myWindow: WindowPtr;    {pointer to wRecord}
    whichWindow: WindowPtr; {pointer to window in which mouse button was pressed}


PROCEDURE SetUpMenus;
{ Set up menus and menu bar }

  VAR i: INTEGER;

  BEGIN
  { Read menu descriptions from resource file into memory and store handles }
  { in myMenus array }
  myMenus[appleM] := GetMenu(appleID); {read Apple menu from resource file}
  AddResMenu(myMenus[appleM],'DRVR');  {add desk accessory names to Apple menu}
  myMenus[fileM] := GetMenu(fileID);   {read File menu from resource file}
  myMenus[editM] := GetMenu(editID);   {read Edit menu from resource file}

  FOR i:=1 TO menuCount DO InsertMenu(myMenus[i],0);  {install menus in menu bar }
  DrawMenuBar;                                        { and draw menu bar}
  END;    {of SetUpMenus}


PROCEDURE DoCommand (mResult: LONGINT);
{ Execute command specified by mResult, the result of MenuSelect }

  VAR theItem: INTEGER;  {menu item number from mResult low-order word}
      theMenu: INTEGER;  {menu number from mResult high-order word}
      name: Str255;      {desk accessory name}
      temp: INTEGER;

  BEGIN
  theItem := LoWord(mResult);             {call Toolbox Utility routines to set }
  theMenu := HiWord(mResult);             { menu item number and menu number}

  CASE theMenu OF                         {case on menu ID}

  appleID:
    BEGIN                                  {call Menu Manager to get desk accessory }
    GetItem(myMenus[appleM],theItem,name); { name, and call Desk Manager to open }
    temp := OpenDeskAcc(name);             { accessory (OpenDeskAcc result not used)}
    SetPort(myWindow);                     {call QuickDraw to restore application }
    END;    {of appleID}                   { window as grafPort to draw in (may have }
                                           { been changed during OpenDeskAcc)}
  fileID:
    doneFlag := TRUE;             {quit (main loop repeats until doneFlag is TRUE)}

  editID:
    BEGIN                         {call Desk Manager to handle editing command if }
    IF NOT SystemEdit(theItem-1)  { desk accessory window is the active window}
      THEN                        {application window is the active window}
        CASE theItem OF           {case on menu item (command) number}

        cutCommand:    TECut(textH);     {call TextEdit to handle command}
        copyCommand:   TECopy(textH);
        pasteCommand:  TEPaste(textH);
        clearCommand:  TEDelete(textH);

        END;    {of item case}
    END;    {of editID}

  END;    {of menu case}          {to indicate completion of command, call }
  HiliteMenu(0);                  { Menu Manager to unhighlight menu title }
                                  { (highlighted by MenuSelect)}
  END;  {of DoCommand}


BEGIN    {main program}
{ Initialization }
InitGraf(@thePort);           {initialize QuickDraw}
InitFonts;                    {initialize Font Manager}
FlushEvents(everyEvent,0);    {call OS Event Manager to discard any previous events}
InitWindows;                  {initialize Window Manager}
InitMenus;                    {initialize Menu Manager}
TEInit;                       {initialize TextEdit}
InitDialogs(NIL);             {initialize Dialog Manager}
InitCursor;                   {call QuickDraw to make cursor (pointer) an arrow}

SetUpMenus;                   {set up menus and menu bar}
WITH screenBits.bounds DO     {call QuickDraw to set dragging boundaries; ensure at }
  SetRect(dragRect,4,24,right-4,bottom-4); { least 4 by 4 pixels will remain visible}
doneFlag := FALSE;            {flag to detect when Quit command is chosen}

myWindow := GetNewWindow(windowID,@wRecord,POINTER(-1)); {put up application window}
SetPort(myWindow);            {call QuickDraw to set current grafPort to this window}
txRect := thePort^.portRect;  {rectangle for text in window; call QuickDraw to bring }
InsetRect(txRect,4,0);        { it in 4 pixels from left and right edges of window}
textH := TENew(txRect,txRect);        {call TextEdit to prepare for receiving text}

{ Main event loop }
REPEAT                                {call Desk Manager to perform any periodic }
  SystemTask;                         { actions defined for desk accessories}
  TEIdle(textH);                      {call TextEdit to make vertical bar blink}

  IF GetNextEvent(everyEvent,myEvent) {call Toolbox Event Manager to get the next }
    THEN                              { event that the application should handle}
      CASE myEvent.what OF            {case on event type}

      mouseDown:            {mouse button down:  call Window Manager to learn where}
        CASE FindWindow(myEvent.where,whichWindow) OF

        inSysWindow:        {desk accessory window:  call Desk Manager to handle it}
          SystemClick(myEvent,whichWindow);

        inMenuBar:          {menu bar:  call Menu Manager to learn which command, }
          DoCommand(MenuSelect(myEvent.where)); { then execute it}

        inDrag:             {title bar:  call Window Manager to drag}
          DragWindow(whichWindow,myEvent.where,dragRect);

        inContent:                          {body of application window: }
          BEGIN                             { call Window Manager to check whether }
          IF whichWindow <> FrontWindow     { it's the active window and make it }
            THEN SelectWindow(whichWindow)  { active if not}
            ELSE
              BEGIN                         {it's already active:  call QuickDraw to }
              GlobalToLocal(myEvent.where); { convert to window coordinates for }
                                            { TEClick, use Toolbox Utility BitAnd to }
              extended := BitAnd(myEvent.modifiers,shiftKey) <> 0;  { test for Shift }
              TEClick(myEvent.where,extended,textH);   { key down, and call TextEdit }
              END;                                     { to process the event}
          END;    {of inContent}

        END;    {of mouseDown}

      keyDown, autoKey:              {key pressed once or held down to repeat}
        BEGIN
        theChar := CHR(BitAnd(myEvent.message,charCodeMask));  {get the character}
        IF BitAnd(myEvent.modifiers,cmdKey) <> 0  {if Command key down, call Menu }
          THEN DoCommand(MenuKey(theChar))        { Manager to learn which command,}
          ELSE TEKey(theChar,textH);              { then execute it; else pass }
        END;                                      { character to TextEdit}

      activateEvt:
        BEGIN
        IF BitAnd(myEvent.modifiers,activeFlag) <> 0
          THEN                     {application window is becoming active: }
            BEGIN                  { call TextEdit to highlight selection }
            TEActivate(textH);     { or display blinking vertical bar, and call }
            DisableItem(myMenus[editM],undoCommand); { Menu Manager to disable }
            END                    { Undo (since application doesn't support Undo)}
          ELSE
            BEGIN                  {application window is becoming inactive: }
            TEDeactivate(textH);   { unhighlight selection or remove blinking }
            EnableItem(myMenus[editM],undoCommand);  { vertical bar, and enable }
            END;                   { Undo (since desk accessory may support it)}
        END;   {of activateEvt}

      updateEvt:                                 {window appearance needs updating}
        BEGIN
        BeginUpdate(WindowPtr(myEvent.message)); {call Window Manager to begin update}
        EraseRect(thePort^.portRect);            {call QuickDraw to erase text area}
        TEUpdate(thePort^.portRect,textH);       {call TextEdit to update the text}
        EndUpdate(WindowPtr(myEvent.message));   {call Window Manager to end update}
        END;    {of updateEvt}

      END;    {of event case}

UNTIL doneFlag;
END.
